package com.whyt.oauth.auth.conf;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.annotation.Resource;

/**
 * Spring Security配置
 *
 * SecurityConfiguration一定要在ResourceServerConfiguration 之前
 *
 * @author ASUS
 */
@Configuration
@EnableWebSecurity
@SuppressWarnings("all")
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(2)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    /**
     * Security中用于查询用户详细信息的接口
     */
    @Resource
    private UserDetailsService userDetailsService;

    /**
     * 编码器
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder encoder()
    {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(encoder());
    }

    /**
     * password授权模式，需要提供AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception
    {
        return super.authenticationManager();
    }

    /**
     * 这段配置，我认为就是配置Security的认证策略, 每个模块配置使用and结尾。
     * 真正的安全策略配置
     *
     * authorizeRequests()
     *      配置路径拦截，表明路径访问所对应的权限，角色，认证信息。
     * formLogin()
     *      对应表单认证相关的配置
     * logout()
     *      对应了注销相关的配置
     * httpBasic()
     *      可以配置basic登录
     * authenticated()
     *      只验证身份，不校验权限
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        // 禁用默认基本权限认证
        http.httpBasic().disable();
        // 考虑CSRF本质是盗用cookie, 无cookie方案就可以禁用
        http.csrf().disable();
        // 自定义登录页面，formLogin需要在前面，对应表单认证相关的配置，permitAll：表示和登陆相关的接口不需要认证
        http.formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .requestMatchers()
                .antMatchers("/login/**", "/oauth/**")
                .and()
            .authorizeRequests()
                .antMatchers("/fonts/**", "/js/**", "/css/**", "/img/**")
                .permitAll()
                .antMatchers("/oauth/**")
                .authenticated();
    }

    /**
     * 过滤一些静态文件，避开验证类似于：
     * authorizeRequests().antMatchers("/fonts/**", "/js/**", "/css/**", "/img/**")
     *
     * @param web
     * @throws Exception
     */
//    @Override
//    public void configure(WebSecurity web) throws Exception
//    {
//        // super.configure(web);
//        web.ignoring().mvcMatchers("/public/**");
//    }
}
